#ifndef	CLASSIFY_H
#define	CLASSIFY_H

#include "opencv\cv.h"
#include "opencv\highgui.h"

#include <iostream>
#include <fstream>
#include <math.h>
#include <string.h>

#include "svm_light\svm_light_util.h"

using namespace std;

namespace Classify
{
	//dimensions of the hog
#define	N_DIMENSIONS	31*8*16

	//	TRAINER
	void		createClassificator(float window_feature[], cv::Rect window_rect, cv::Rect positive_rects[]);

	void	genTrain(vector<SparseVector> positive, vector<SparseVector> negative, char* filename);
	double	genClassify( char* filename, SparseVector input);

	//	AnnotatedImageComposer
	void		composeImage(cv::Mat final_image);

	SparseVector HOGMatToSparseVector(cv::Mat hog);

	/*! Class for classfying and training classifiers
	*	First add positive and negative examples via the given class methods, then
	*	use train() to train the new model.
	*	Use classify to get the positive or negative classification value of an hypothesis.
	*	To retrain the model, add additional neg./ pos. examples, then use train() again.
	*	@param	char * filename:	The filename were to save and load the classifier. Can be generic, because the
	*								Classifier class always with the initialized filename.
	*	@param	doubel c:			The c value, needed for the training process. Can be changed with setC_Val()
	*								Use train() again so the results of the new c take effect.
	*/

	class Classifier{
	private:
		std::vector <SparseVector> positive;
		std::vector <SparseVector> negative;
		const joachims::MODEL * m;
		char * filename;
		double c;

	public:
		Classifier(char * filename){
			SparseVector positive(0);
			SparseVector negative(0);
			this->filename=filename;
			m=NULL;
		}

		void setFilename(char * filename){
			this->filename=filename;
		}

		//!	add hog mat to negative examples
		void addPositiveExample(cv::Mat in){
#pragma omp critical (classifier)
			positive.push_back(HOGMatToSparseVector(in));
		}
		//!	add hog mat to negative examples
		void addNegativeExample(cv::Mat in){
#pragma omp critical (classifier)
			negative.push_back(HOGMatToSparseVector(in));
		}

		/*!		Train with all found positive and negative examples found so far.
		*		Always use this method if you used the "addPositiveExample" and "addNegativeExample"
		*		functions before.
		*/
		void train(){
#pragma omp critical (classifier)
			{
				SvmLightUtil s=*new SvmLightUtil();
				SvmLightUtil::Parameters p= *new SvmLightUtil::Parameters();
				p.svm_c=0;
				p.kernel_type=SVM_LIGHT_LINEAR;				//linear
				p.model_type=CLASSIFICATION;
				s.train (positive, negative, N_DIMENSIONS , filename, 1.0, p);
				printf("We have our model.\n");
				loadModel();
			}
		}

		void loadModel(){
#pragma omp critical (classifier)
			{
				SvmLightUtil s =* new SvmLightUtil();
				m = s.getModel(filename);
			}
		}

		/*!	This function classifies ONE test example with a trained model from the specific filename.
		*	@returns	Double value d with:
		*	1 < d:		Positive hit (100% sure)	
		*	0 < d < 1:	Positive hit with d probability
		*	-1 < d < 0:	Negative hit with d probability
		*	d < -1:		Negative hit (100% sure)
		*/

		double classify(cv::Mat in){
#pragma omp critical (classifier)
			{
				if (m == NULL)
					loadModel();

			}
			SvmLightUtil s =* new SvmLightUtil();
			SparseVector e=HOGMatToSparseVector(in);
			return s.classify(e, N_DIMENSIONS , m);
		}
	};

	void					showAndAnnotateImg(std::string filepath, std::string text);
	void					writeFile(std::string text, std::string path);
	std::vector<cv::Rect>	readFile(char* filepath);
}

#endif